#include "StdAfx.h"
#include <stdio.h>
#include <stdlib.h>
#include "data_buffer.h"

BufferChain::BufferChain(void)
{
	m_pBuffer=NULL;
}
BufferChain::~BufferChain(void)
{
	free(m_pBuffer);
	m_pBuffer=NULL;
}
void BufferChain::InitBufferChain(void)
{
	m_pBuffer=(struct buffer_chain *)malloc(sizeof(struct buffer_chain));
	if(!m_pBuffer)
		printf("failed to alloc memory!\n");
	m_pBuffer->p_head		 =	NULL;
	m_pBuffer->p_tail		 =	NULL;
	m_pBuffer->buffer_size = 0;
}
/*
*   Function:AddToTail
*	Used to add data the tail of chain
*/
void BufferChain::AddToTail(char *p_data,int data_len)
{
	const char *p_buff;

	if(NULL == p_data) return;
	if(0 == data_len) return;
	
	p_buff = (const char *)p_data;
	m_pBuffer->buffer_size+=data_len;

	/*The unit is not full*/
	if(m_pBuffer->p_tail!=NULL && m_pBuffer->p_tail->end_pos<BUFFER_UNIT_SIZE)
	{
		int len = min(data_len, BUFFER_UNIT_SIZE - m_pBuffer->p_tail->end_pos);
		memcpy(m_pBuffer->p_tail->data_buffer+m_pBuffer->p_tail->end_pos,p_buff,len);
		m_pBuffer->p_tail->end_pos+=len;
		p_buff+=len;
		data_len-=len;
	}
	while(data_len>0)
	{
		int copy_len=min(data_len,BUFFER_UNIT_SIZE);
		struct buffer_chain_element  *p_newUnitMem=(struct buffer_chain_element *)malloc(sizeof(struct buffer_chain_element));
		p_newUnitMem->end_pos=copy_len;
		p_newUnitMem->start_pos=0;
		p_newUnitMem ->next = NULL;
		memcpy(p_newUnitMem->data_buffer,p_buff,copy_len);
		p_buff+=copy_len;
		data_len-=copy_len;

		if(m_pBuffer->p_tail!=NULL)
		{
			m_pBuffer->p_tail->next=p_newUnitMem;
			m_pBuffer->p_tail = p_newUnitMem;
		}
		else
		{
			m_pBuffer->p_head=p_newUnitMem;
			m_pBuffer->p_tail=p_newUnitMem;
		}
		//p_newUnitMem->next=NULL;
		//m_pBuffer->p_tail=p_newUnitMem;
	}
	

}
/*
*   Function:FreeMemFromHead
*	Used to remove the first element in chain
*/
void BufferChain::FreeMemFromHead(int data_len)
{
	struct buffer_chain_element  *p_buffTmp;
	if(m_pBuffer->p_head==NULL) return;
	if(data_len>m_pBuffer->buffer_size)return;

	while(data_len>0)
	{
		int rm_len=data_len;
		if(rm_len>=(m_pBuffer->p_head->end_pos-m_pBuffer->p_head->start_pos))
		{
			p_buffTmp=m_pBuffer->p_head;
			rm_len=m_pBuffer->p_head->end_pos-m_pBuffer->p_head->start_pos;
			m_pBuffer->p_head = p_buffTmp->next;
			free(p_buffTmp);
			if(m_pBuffer->p_head==NULL)
				m_pBuffer->p_tail=NULL;
		}
		else
			m_pBuffer->p_head->start_pos+=rm_len;

		m_pBuffer->buffer_size-=rm_len;
		data_len-=rm_len;
	}
	
}
/*
*   Function:GetDataFromHead
*	Used to get data from head of chain
*	data_len:	data length to get 
*	p_retBuff:	buffer to store data return;
*/
void BufferChain::GetDataFromHead(void *p_retBuff,int data_len)
{
	char *p_ret=(char *)p_retBuff;
	struct buffer_chain_element  *p_retTmp;
	if(p_retBuff==NULL) return;
	if(data_len>m_pBuffer->buffer_size)return;
	p_retTmp=m_pBuffer->p_head;
	while(data_len>0)
	{
		int ret_len=data_len;
		if(ret_len>(p_retTmp->end_pos-p_retTmp->start_pos))
		{
			ret_len=p_retTmp->end_pos-p_retTmp->start_pos;
		}
		memcpy(p_ret,p_retTmp->data_buffer+p_retTmp->start_pos,ret_len);
		p_ret+=ret_len;
		data_len-=ret_len;
		p_retTmp = p_retTmp->next;
	}
}

void BufferChain::GetDataBuffer(char **buffer, int *len)
{
	if(m_pBuffer->p_head!=NULL)
	{
		*len = m_pBuffer->p_head->end_pos - m_pBuffer->p_head->start_pos;
		*buffer = m_pBuffer->p_head->data_buffer + m_pBuffer->p_head->start_pos;
	}
}